﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Zgq.CommonTools
{
    public static class StackTraceHelper
    {
        /// <summary>
        /// 获取当前堆栈的上级调用方法列表,直到最终调用者,只会返回调用的各方法,而不会返回具体的出错行数
        /// </summary>
        /// <param name="sfsIdx">起始位置</param>
        /// <param name="maxNum">最大层次数</param>
        /// <param name="breakStr">跳过的方法名（多个中间以逗号分隔）</param>
        /// <returns></returns>
        public static string GetStackTraceModelName(int sfsIdx = 1, int maxNum = -1, string breakStr = null)
        {
            if (sfsIdx < 1) sfsIdx = 1;
            //当前堆栈信息
            System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
            System.Diagnostics.StackFrame[] sfs = st.GetFrames();
            //过虑的方法名称,以下方法将不会出现在返回的方法调用列表中
            string _filterdName = "ResponseWrite,ResponseWriteError,";
            string _methodName = string.Empty;

            StringBuilder methodInfo = new StringBuilder();
            if (maxNum < 0)
                maxNum = sfs.Length;
            else if (maxNum > sfs.Length) maxNum = sfs.Length;

            for (int i = sfsIdx; i < maxNum; ++i)
            {
                //非用户代码,系统方法及后面的都是系统调用，不获取用户代码调用结束
                if (System.Diagnostics.StackFrame.OFFSET_UNKNOWN == sfs[i].GetILOffset()) break;

                var method = sfs[i].GetMethod();//方法
                _methodName = method.Name;//方法名称

                if (breakStr != null)
                    if (breakStr.Contains(_methodName)) break;
                if (_filterdName.Contains(_methodName)) continue;

                //methodInfo.AppendFormat("{0}.{1}()->", method.DeclaringType.FullName, _methodName);
                methodInfo.AppendFormat("{0}.{1}()->", method.DeclaringType.Name, _methodName);
            }
            st = null;
            sfs = null;
            _filterdName = _methodName = null;
            if (methodInfo.Length < 2) return null;

            return methodInfo.Remove(methodInfo.Length - 2, 2).ToString();//.TrimEnd('-', '>');
        }
    }
}
